home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / DIAGXPRT.PAK / SETUP.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  21KB  |  833 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // (C) Copyright 1993, 1995 by Borland International, All Rights Reserved
  4. //
  5. //----------------------------------------------------------------------------
  6. #include <owl/pch.h>
  7. #include <owl/dialog.h>
  8. #include <owl/clipboar.h>
  9. #include <owl/clipview.h>
  10. #include "diagxprt.rh"
  11. #include "setup.h"
  12. #include "diagxprt.h"
  13. #include <stdio.h>
  14.  
  15. //
  16. //  The diagnostic setup dialog box is divided in 2 main groups:
  17. //   - the system group (TSysGroup->TGroup);
  18. //   - the user group (TUsrGroup->TGroup).
  19. //
  20. //  Each group is a list of items (TSetupItem).
  21. //  Items belonging to the system group (TSysItem->TSetupItem) are
  22. //  different than items belonging to the user group (TUsrItem->TSetupItem)
  23. //  in that the setup infos are not maintained the same way in OWL.INI.
  24. //
  25. //  Each item TSysItem and TUsrItem is attached to a set of child windows
  26. //  in the dialog box. Each such set of windows is abstracted thru a class:
  27. //  TUsrWindow and TSysWindow respectively. Each of those classes is
  28. //  generated by a class template, which parametrizes the exact contents
  29. //  of the set of windows: TRadioButton/TRadioButton and TStatic/TEdit resp.
  30. //
  31. //  The number of windows set is limited (by the area in the dialog box);
  32. //  the number of items is NOT limited. Scroll bars are displayed when
  33. //  necessary. Those scrollbars are abstracted thru the class TGroupScroll.
  34. //  Therefore each group maintains two arrays: an array of items TItemsArray
  35. //  and an array of window sets TWindowArray.
  36. //
  37.  
  38.  
  39. //
  40. // Utility function to copy diagnostic code to clipboard so that user
  41. // can paste into appropriate source file
  42. //
  43. void
  44. CopyToClipboard(TWindow* w, char* descr, char* className)
  45. {
  46.   // Generate a C++ example on the clipboard, which is a very trivial
  47.   // string subsitution operation.
  48.   //
  49.   string pattern(
  50.     "// Diagnostic: %s\n"
  51.     "DIAG_DEFINE_GROUP_INIT(OWL_INI, %s, 1, 0);\n"
  52.     "//TRACEX(%s, errLevel, \042A comment \042 << aFunction());\n"
  53.    );
  54.  
  55.   pattern.substring("%s") = descr;
  56.   pattern.substring("%s") = className;
  57.   pattern.substring("%s") = className;
  58.  
  59.   TClipboard c(*w);
  60.   c.EmptyClipboard();
  61.   HANDLE hData = ::GlobalAlloc(GMEM_SHARE, pattern.length()+1);
  62.   char far* pData = (char far*)::GlobalLock(hData);
  63.  
  64.   pattern.copy(pData, pattern.length()+1);
  65.  
  66.   ::GlobalUnlock(hData);
  67.   c.SetClipboardData(CF_TEXT, hData);
  68. }
  69.  
  70. //
  71. //  class TSetupItem
  72. //
  73.  
  74. TSetupItem::TSetupItem(char* c, char* d)
  75. :
  76.   EnableCheck(0),
  77.   level(0),
  78.   Class(c),
  79.   Descr(d)
  80. {
  81. }
  82.  
  83. void
  84. TSetupItem::operator =(TBaseSetupWindow& w)
  85. {
  86.   // Unmap from a physical set of windows: set the enability and
  87.   // warning level accordingly to the setup window:
  88.   //
  89.   SetEnable(w.GetEnable());
  90.   SetLevel(w.GetLevel());
  91. }
  92.  
  93. void
  94. TSetupItem::Load()
  95. {
  96.   // Loads itself from .ini file - loads the diagnostic classname and the
  97.   // diagnostic description:
  98.   //
  99.   char b[80];
  100.   GetPrivateProfileString(GetSection(), Class.c_str(), "0 0", b, sizeof b,
  101.                           GetIniFile());
  102.   sscanf(b, "%d %d", &bEnable, &level);
  103.   if (Descr == "") {
  104.     GetPrivateProfileString(GetSectionDesc(), Class.c_str(), Class.c_str(),
  105.                             b, sizeof b, GetIniFile());
  106.     Descr = b;
  107.   }
  108. }
  109.  
  110. void
  111. TSetupItem::Save()
  112. {
  113.   // Save itself to the .ini file - save the diagnostic classname and the
  114.   // diagnostic description:
  115.   //
  116.   char b[20];
  117.   sprintf(b, "%d %d", bEnable, level);
  118.   WritePrivateProfileString(GetSection(), Class.c_str(), b, GetIniFile());
  119.   WritePrivateProfileString(GetSectionDesc(), Class.c_str(), Descr.c_str(), GetIniFile());
  120. }
  121.  
  122. //
  123. //  class TDiagEnable
  124. //
  125.  
  126. DEFINE_RESPONSE_TABLE1(TDiagEnable, TCheckBox)
  127.   EV_NOTIFY_AT_CHILD(BN_CLICKED, BNClicked),
  128. END_RESPONSE_TABLE;
  129.  
  130. //  TDiagEnable provides an abstraction for the small check box associated
  131. //  to each setup item. This checkbox enables of disables the associated
  132. //  setup item. But the checkbox can itself be disabled (by a upper level
  133. //  checkbox).
  134. //
  135. void
  136. TDiagEnable::BNClicked()
  137. {
  138.   TCheckBox::BNClicked();
  139.   EnableWindow(true);
  140. }
  141.  
  142. bool
  143. TDiagEnable::EnableWindow(bool enable)
  144. {
  145.   bool ret = TCheckBox::EnableWindow(enable);
  146.   if (enable)
  147.     enable = GetCheck();
  148.   if (W0) W0->EnableWindow(enable);
  149.   if (W1) W1->EnableWindow(enable);
  150.   if (S0) S0->EnableWindow(enable);
  151.   if (S1) S1->EnableWindow(enable);
  152.   return ret;
  153. }
  154.  
  155. //
  156. //  TMainEnable provides the abstraction for the main checkbox which
  157. //  enables of disables ALL the diagnostic groups. It knows how to save/load
  158. //  it state from the .ini file:
  159. //
  160. char* TMainEnable::Class = "Enabled";
  161.  
  162. TMainEnable::TMainEnable(TWindow* p, int n, TGroup* g1, TGroup* g2) :
  163.   TDiagEnable(p, n, g1, g2)
  164. {
  165.   Create();
  166.   Load();
  167. }
  168.  
  169. void
  170. TMainEnable::Load()
  171. {
  172.   char b[80];
  173.   GetPrivateProfileString(SYS_CLS, Class, "0", b, sizeof(b), SYS_INI);
  174.   SetCheck(atoi(b));
  175.   TDiagEnable::EnableWindow(true);
  176. }
  177.  
  178. void
  179. TMainEnable::Save()
  180. {
  181.   char b[80];
  182.   sprintf(b, "%d", GetCheck() != 0);
  183.   WritePrivateProfileString(SYS_CLS, Class, b, SYS_INI);
  184. }
  185.  
  186.  
  187. //
  188. //  TGroup is the base class for diagnostic groups. TGroup knows how to
  189. //  enable/disable itself (by enabling/disabling all the associated setup
  190. //  items), to load/save from the .ini file and to map/unmap its setup
  191. //  items to the associated windows sets. The purpose of the map/unmap
  192. //  operations is to allow setup items to be scrolled.
  193. //
  194.  
  195. void
  196. TGroup::EnableWindow(bool bEnable)
  197. {
  198.   for (int i = 0; i < Windows.GetItemsInContainer(); i++)
  199.     Windows[i]->EnableWindow(bEnable);
  200. }
  201.  
  202. void
  203. TGroup::Load()
  204. {
  205.   for (int i = 0; i < Items.GetItemsInContainer(); i++)
  206.     Items[i]->Load();
  207. }
  208.  
  209. void
  210. TGroup::Save()
  211. {
  212.   Cleanup();
  213.   for (int i = 0; i < Items.GetItemsInContainer(); i++)
  214.     Items[i]->Save();
  215. }
  216.  
  217. int
  218. TGroup::Map(int x)
  219. {
  220.   // May have to re-validate <x>
  221.   //
  222.   if (x == MapAsBefore)
  223.     x = scrollPos;
  224.   if (x > Items.GetItemsInContainer() || x == MapToBottom)
  225.     x = Items.GetItemsInContainer() - Windows.GetItemsInContainer();
  226.   if (x < 0 || x == MapToTop)
  227.     x = 0;
  228.   scrollPos = x;
  229.  
  230.   // Map each item to a window, as long as they fit
  231.   //
  232.   for (int i = 0; i < Windows.GetItemsInContainer(); i++, x++) {
  233.     if (x < Items.GetItemsInContainer()) {
  234.       *Windows[i] = *Items[x];
  235.       Windows[i]->EnableWindow(IsEnable());
  236.     } else
  237.       *Windows[i] = 0;      // No more item: "empty" the associated window
  238.   }
  239.   return scrollPos;
  240. }
  241.  
  242. int
  243. TGroup::UnMap()
  244. {
  245.   int i, x;
  246.   for (i = 0, x = scrollPos; i < Windows.GetItemsInContainer(); i++, x++) {
  247.     if (x < Items.GetItemsInContainer())
  248.       *Items[x] = *Windows[i];
  249.   }
  250.   return scrollPos;
  251. }
  252.  
  253. static void
  254. DeleteWindows(TBaseSetupWindow*& w, void*)
  255. {
  256.   delete w;
  257. }
  258.  
  259. static void
  260. DeleteItems(TSetupItem*& s, void*)
  261. {
  262.   delete s;
  263. }
  264.  
  265. TGroup::~TGroup()
  266. {
  267.   Windows.ForEach(DeleteWindows, 0);
  268.   Windows.Flush();
  269.   Items.ForEach(DeleteItems, 0);
  270.   Items.Flush();
  271. }
  272.  
  273.  
  274.  
  275. //
  276. //  class TSysGroup
  277. //
  278.  
  279. TSysGroup::TSysGroup(TWindow *Dialog, int nID)
  280. {
  281.   // Create the child windows
  282.   //
  283.   for (int i = 0; Dialog->GetDlgItem(nID + i*4); i++)
  284.     Windows.Add(new TSysWindow(Dialog, nID + i*4));
  285.  
  286.   // Create the predefined system items (read from resources)
  287.   //
  288.   HRSRC hRes = GetApplicationObject()->FindResource(IDR_SYS_ITEMS, RT_RCDATA);
  289.   if (hRes) {
  290.     HGLOBAL hData = GetApplicationObject()->LoadResource(hRes);
  291.     if (hData) {
  292.       LPSTR pData = (LPSTR)::LockResource(hData);
  293.       // pData now points to a set of strings
  294.  
  295.       LPSTR pC = pData;
  296.       LPSTR pD;
  297.  
  298.       while(pC && *pC) {
  299.         char name[128];
  300.         char desc[128];
  301.         pD = pC + strlen(pC) + 2;
  302.         lstrcpy(name, pC);
  303.         lstrcpy(desc, pD);
  304.         Items.Add(new TSysItem(name, desc));
  305.         pC = pD + strlen(pD) + 2;
  306.       }
  307. #if !defined(BI_PLAT_WIN32)
  308.       ::UnlockResource(hData);
  309. #endif
  310.     }
  311. #if !defined(BI_PLAT_WIN32)
  312.     ::FreeResource(hData);
  313. #endif
  314.   }
  315.   // Load the values associated to each item
  316.   TGroup::Load();
  317. }
  318.  
  319. void
  320. TSysGroup::Cleanup()
  321. {
  322.   WritePrivateProfileString(SYS_CLS, 0, 0, SYS_INI);
  323.   WritePrivateProfileString(SYS_DSC, 0, 0, SYS_INI);
  324. }
  325.  
  326. //
  327. //  class TUsrGroup
  328. //
  329.  
  330. TUsrGroup::TUsrGroup(TWindow *Dialog, int nID)
  331. {
  332.   // Create the child windows
  333.   //
  334.   int i;
  335.   for (i = 0; Dialog->GetDlgItem(nID + i*4); i++)
  336.     Windows.Add(new TUsrWindow(Dialog, nID + i*4));
  337.  
  338.   // Create the setup items (loaded from IniFile)
  339.   //
  340.   const int s = 4096;
  341.   char *p, *b = new char[s];
  342.   GetPrivateProfileString(USR_DSC, 0, "", b, s, USR_INI);
  343.   for (i = 0, p = b; p && *p; i++, p += strlen(p) + 1)
  344.     Items.Add(new TUsrItem(p));
  345.   delete b;
  346.  
  347.   // Load the values associated to each item
  348.   //
  349.   TGroup::Load();
  350. }
  351.  
  352. void
  353. TUsrGroup::Cleanup()
  354. {
  355. //  WritePrivateProfileString(USR_CLS, 0, 0, USR_INI);
  356.   WritePrivateProfileString(USR_DSC, 0, 0, USR_INI);
  357. }
  358.  
  359. //
  360. //  TSizableDialog makes a dialog sizable. Two sizes are defined: a small
  361. //  size and a large size. Call the Toggle function to switch to any size.
  362. //  To determine the size, define a dummy control in the dialog which
  363. //  provides the upper-right corner of the small size.
  364. //  TSizableDialog also know how to center itself accordingly to the parent
  365. //  window, and how to re-adjust its position after being centered, if gone
  366. //  out of view.
  367. //
  368.  
  369. void
  370. TSizableDialog::SetupWindow()
  371. {
  372.   TDialog::SetupWindow();
  373.   HWND hBox = GetDlgItem(nBoxID);
  374.   if (hBox) {
  375.     ::ShowWindow(hBox, SW_HIDE);
  376.     TRect rSmall, rLarge;
  377.     ::GetWindowRect(hBox, (LPRECT)&rSmall);
  378.     GetWindowRect(rLarge);
  379.     small.cx = rSmall.left - rLarge.left;
  380.     small.cy = rSmall.top - rLarge.top;
  381.     large = rLarge.Size();
  382.     tSize = t_max;
  383.     bMaximized = true;
  384.  
  385.     // Tolerate some inaccuracy on the positionning of the small box...
  386.     //
  387.     if (abs(small.cx - large.cx) < 4)
  388.       small.cx = large.cx;
  389.     if (abs(small.cy - large.cy) < 4)
  390.       small.cy = large.cy;
  391.     Toggle(t_min);
  392.   }
  393.   Center();
  394. }
  395.  
  396. void
  397. TSizableDialog::Toggle(int tType)
  398. {
  399.   TSize newSize;
  400.   if (tType == t_minmax)
  401.     tType = (tSize == t_min) ? t_max : t_min;
  402.  
  403.   tSize = tType;
  404.   switch (tType) {
  405.     case t_min:
  406.       newSize = small;
  407.       break;
  408.     case t_max:
  409.       newSize = large;
  410.       break;
  411.     default:
  412.       return;
  413.   }
  414.   bMaximized = tType != t_max;
  415.   SetWindowPos(0, TRect(TPoint(0, 0), newSize), SWP_NOZORDER|SWP_NOMOVE);
  416. //  EnableControls();
  417. }
  418.  
  419. void
  420. TSizableDialog::EnableControls()
  421. {
  422.   TRect rParent = GetWindowRect();
  423.   HWND hChld = GetWindow(GW_CHILD);
  424.   while (hChld) {
  425.     POINT pt[2];
  426.     ::GetWindowRect(hChld, (RECT*)&pt);
  427.     if (!PtInRect(&rParent, pt[0]))
  428.       ::EnableWindow(hChld, 0);
  429.     hChld = ::GetWindow(hChld, GW_HWNDNEXT);
  430.   }
  431. }
  432.  
  433. void
  434. TSizableDialog::Center()
  435. {
  436.   TRect rPar;
  437.   TRect rDlg;
  438.   GetWindowRect(rDlg);
  439.   HWND hParent = GetParent();
  440.   if (!hParent)
  441.     hParent = GetDesktopWindow();
  442.   ::GetWindowRect(hParent, &rPar);
  443.  
  444.   int wDlgWidth = rDlg.Width();
  445.   int wDlgHeight = (rDlg.bottom - rDlg.top);
  446.  
  447.   int w = (rPar.right - rPar.left) - wDlgWidth;
  448.   int h = (rPar.bottom - rPar.top) - wDlgHeight;
  449.  
  450.   int x = rPar.left + (w / 2);
  451.   int y = rPar.top + (h / 2);
  452.  
  453.   MoveWindow(x, y, wDlgWidth , wDlgHeight, false);
  454.   AdjustPos();
  455. }
  456.  
  457. void
  458. TSizableDialog::AdjustPos(void)
  459. {
  460.   int W = GetSystemMetrics(SM_CXSCREEN);
  461.   int H = GetSystemMetrics(SM_CYSCREEN);
  462.  
  463.   TRect r = GetWindowRect();
  464.   int w = r.Width();
  465.   int h = r.Height();
  466.  
  467.   if (r.left < 0)
  468.     r.left = 0;
  469.   if (r.top < 0)
  470.     r.top = 0;
  471.   if (r.right > W)
  472.     r.left = W - w;
  473.   if (r.bottom > H)
  474.     r.top -= (H - h);
  475.  
  476.   SetWindowPos(0, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  477. }
  478.  
  479.  
  480. //
  481. //  TGroupScroll provides the abstraction for a diagnostic group scrollbar.
  482. //  Associated to a diagnostic group, TGroupScroll simply map/unmap the
  483. //  diagnostic group on scroll events. It also knows how to hide itself when
  484. //  scrolling is irrelevant for that group (and show back if necessary):
  485.  
  486. DEFINE_RESPONSE_TABLE1(TGroupScroll, TScrollBar)
  487.   EV_WM_VSCROLL,
  488. END_RESPONSE_TABLE;
  489.  
  490. TGroupScroll::TGroupScroll(TWindow* w, int i, TGroup* g)
  491.   : group(g), x(0), TScrollBar(w, i)
  492. {
  493.   Create();
  494.   Initialize(0);
  495. }
  496.  
  497. void
  498. TGroupScroll::Initialize(int pos)
  499. {
  500.   min = 0;
  501.   max = group->Items.GetItemsInContainer() - group->Windows.GetItemsInContainer();
  502.  
  503.   if (max <= min)
  504.     ShowWindow(SW_HIDE);    // Hide itself because scrolling is irrelevant
  505.  
  506.   else {
  507.     SetRange(min, max);
  508.     TScrollBar::SetPosition(x = pos);
  509.     EndScroll();
  510.     PageMagnitude = group->Windows.GetItemsInContainer() - 1;
  511.     ShowWindow(SW_SHOW);    // Show back itself, in case was previously hidden
  512.   }
  513. }
  514.  
  515. void
  516. TGroupScroll::EvVScroll(uint code, uint pos, HWND /*hCtl*/)
  517. {
  518.   switch (code) {
  519.     case SB_LINEDOWN:      if (x < max) SetPosition(x + LineMagnitude); break;
  520.     case SB_LINEUP:        if (x > min) SetPosition(x - LineMagnitude); break;
  521.     case SB_PAGEDOWN:      if (x < max) SetPosition(x + PageMagnitude); break;
  522.     case SB_PAGEUP:        if (x > min) SetPosition(x - PageMagnitude); break;
  523.     case SB_THUMBPOSITION: SetPosition(pos); break;
  524.     case SB_ENDSCROLL:     EndScroll(); break;
  525.   }
  526. }
  527.  
  528. void
  529. TGroupScroll::SetPosition(int pos)
  530. {
  531.   x = pos;
  532.   if (x < min) x = min;
  533.   if (x > max) x = max;
  534.   TScrollBar::SetPosition(x);
  535.  
  536.   // Perform the logical scroll by first unmaping the group and then
  537.   // by maping it to the new position:'
  538.   //
  539.   group->UnMap();
  540.   group->Map(x);
  541. }
  542.  
  543. void
  544. TGroupScroll::EndScroll()
  545. {
  546.   ::EnableScrollBar(*this, SB_CTL, ESB_ENABLE_BOTH);
  547.   if (x == min)
  548.     ::EnableScrollBar(*this, SB_CTL, ESB_DISABLE_LTUP);
  549.   if (x == max)
  550.     ::EnableScrollBar(*this, SB_CTL, ESB_DISABLE_RTDN);
  551.   if (::GetFocus()) {
  552.     ::InvalidateRect(::GetFocus(), 0, true);
  553.     ::UpdateWindow(::GetFocus());
  554.   }
  555. }
  556.  
  557. //
  558. //  TSetupDialog drives the setup diagnostic dialog box
  559. //
  560.  
  561. DEFINE_RESPONSE_TABLE1(TSetupDialog, TDialog)
  562.   EV_COMMAND(IDC_MORE, CmZoom),
  563.   EV_COMMAND(IDOK, CmOk),
  564.   EV_COMMAND(IDC_ADD, CmAddUsr),
  565.   EV_COMMAND(IDC_DEL, CmDelUsr),
  566.   EV_COMMAND(IDC_EDT, CmEdtUsr),
  567. END_RESPONSE_TABLE;
  568.  
  569. void
  570. TSetupDialog::SetupWindow()
  571. {
  572.   TSizableDialog::SetupWindow();
  573.  
  574.   // Create the two groups:
  575.   //
  576.   SysGroup = new TSysGroup(this, ID_SYS_CHECK);
  577.   UsrGroup = new TUsrGroup(this, ID_USR_CHECK);
  578.  
  579.   // Create the master enable switch and make it known to each group:
  580.   //
  581.   MainEnable = new TMainEnable(this, ID_SYS_ENABLE, SysGroup, UsrGroup);
  582.   SysGroup->SetMainSwitch(MainEnable);
  583.   UsrGroup->SetMainSwitch(MainEnable);
  584.  
  585.   // Map each group to the first position:
  586.   //
  587.   SysGroup->Map(0);
  588.   UsrGroup->Map(0);
  589.  
  590.   // Create the two group scrollbars and attach them to their groups:
  591.   //
  592.   SysScroll = new TGroupScroll(this, IDC_SYS_SCROLL, SysGroup);
  593.   UsrScroll = new TGroupScroll(this, IDC_USR_SCROLL, UsrGroup);
  594.  
  595.   // Finally, create the actions buttons and update their enable states:
  596.   //
  597.   pDel = new TButton(this, IDC_DEL);
  598.   pDel->Create();
  599.   pEdt = new TButton(this, IDC_EDT);
  600.   pEdt->Create();
  601.   UpdateButtons();
  602. }
  603.  
  604. void
  605. TSetupDialog::CleanupWindow()
  606. {
  607.   // Delete everybody
  608.   //
  609.   delete MainEnable;
  610.   delete UsrScroll;
  611.   delete SysScroll;
  612.   delete SysGroup;
  613.   delete UsrGroup;
  614.   delete pDel;
  615.   delete pEdt;
  616. }
  617.  
  618. void
  619. TSetupDialog::CmZoom()
  620. {
  621.   // The uses clicked on the <More/Less> button: resize the dialog box
  622.   // and update the button title accordingly:
  623.   //
  624.   Toggle(TSizableDialog::t_minmax);
  625.   SetDlgItemText(IDC_MORE, !IsMaximized()? "<<< &Less" : "&More >>>");
  626. }
  627.  
  628. void
  629. TSetupDialog::CmOk()
  630. {
  631.   // The user validated the changes: unmap to get the physical states and
  632.   // save each group:
  633.   //
  634.   SysGroup->UnMap();
  635.   UsrGroup->UnMap();
  636.   SysGroup->Save();
  637.   UsrGroup->Save();
  638.   MainEnable->Save();
  639.   TSizableDialog::CmOk();
  640. }
  641.  
  642. void
  643. TSetupDialog::CmAddUsr()
  644. {
  645.   // The user selected the 'Add User Group' command. Execute the AddUser
  646.   // dialog box
  647.   //
  648.   TAddUsrDialog Dialog(this);
  649.   if (Dialog.Execute() == IDOK) {
  650.     // Unmap the user group to not lose the last changes, append
  651.     // the new user group to the end of the group and map the group
  652.     // by positionning to the bottom:
  653.     //
  654.     UsrGroup->UnMap();
  655.     UsrGroup->Items.Add(new TUsrItem(Dialog.Class, Dialog.Descr));
  656.  
  657.     int x = UsrGroup->Map(TGroup::MapToBottom);
  658.  
  659.     // Don't forget to reset the scrollbar:
  660.     //
  661.     if (UsrScroll)
  662.       UsrScroll->Initialize(x);
  663.   }
  664.   UpdateButtons();
  665. }
  666.  
  667. void
  668. TSetupDialog::CmDelUsr()
  669. {
  670.   // The user selected the 'Delete User Group' command. Execute the DelUser
  671.   // dialog box
  672.   //
  673.   TDelUsrDialog Dialog(this, &UsrGroup->Items);
  674.   if (Dialog.Execute() == IDOK) {
  675.     // Unmap the user group to not lose the last changes, delete
  676.     // the chosen user group re-map the group:
  677.     //
  678.     int x = UsrGroup->UnMap();
  679.     UsrGroup->Items.Detach(Dialog.nSel);
  680.     x = UsrGroup->Map(x - 1);
  681.  
  682.     // Don't forget to reset the scrollbar:
  683.     //
  684.     if (UsrScroll)
  685.       UsrScroll->Initialize(x);
  686.   }
  687.   UpdateButtons();
  688. }
  689.  
  690. void
  691. TSetupDialog::CmEdtUsr()
  692. {
  693.   // The user selected the 'Edit User Group' command. Execute the EdtUser
  694.   // dialog box
  695.   //
  696.   TEdtUsrDialog Dialog(this, &UsrGroup->Items);
  697.   if (Dialog.Execute() == IDOK) {
  698.     UsrGroup->Map(TGroup::MapAsBefore);
  699.   }
  700. }
  701.  
  702. void
  703. TSetupDialog::UpdateButtons()
  704. {
  705.   // Can only edit/delete not empty user group!
  706.   //
  707.   bool bEnable = UsrGroup->Items.GetItemsInContainer() > 0;
  708.   pDel->EnableWindow(bEnable);
  709.   pEdt->EnableWindow(bEnable);
  710. }
  711.  
  712. //
  713. //  TAddUsrDialog: Prompts the user for two informations - a diagnostic
  714. //  classname and a diagnostic description. Require the classname and
  715. //  defaults the description to the classname.
  716. //
  717.  
  718. DEFINE_RESPONSE_TABLE1(TAddUsrDialog, TDialog)
  719.   EV_COMMAND(IDOK, CmOk),
  720. END_RESPONSE_TABLE;
  721.  
  722. void
  723. TAddUsrDialog::CmOk()
  724. {
  725.   ::GetWindowText(GetDlgItem(IDC_DESCR), Descr, sizeof(Descr));
  726.   ::GetWindowText(GetDlgItem(IDC_CLASS), Class, sizeof(Class));
  727.   if (!*Class) {
  728.     // Classname is required
  729.     //
  730.     MessageBox(
  731.       string(*GetModule(), IDS_ERR_ADD_TXT).c_str(),
  732.       string(*GetModule(), IDS_ERR_ADD_CAP).c_str(),
  733.       MB_OK|MB_ICONHAND);
  734.     ::SetFocus(GetDlgItem(IDC_CLASS));
  735.     return;
  736.   }
  737.   if (!*Descr)
  738.     // Defaults the description to the classname
  739.     //
  740.     strcpy(Descr, Class);
  741.  
  742.   // Put the template on the clipboard
  743.   //
  744.   CopyToClipboard(this, Descr, Class);
  745.  
  746.   TDialog::CmOk();
  747. }
  748.  
  749. //
  750. //  TItemsDialog: serves as a base class to the dialogs which need to
  751. //  show to the user a list of setup items. Know how to fill itself,
  752. //  given an array of setup items.
  753. //
  754.  
  755. DEFINE_RESPONSE_TABLE1(TItemsDialog, TDialog)
  756.   EV_COMMAND(IDOK, CmOk),
  757.   EV_LBN_DBLCLK(IDC_LIST, LBDblClk),
  758.   EV_LBN_SELCHANGE(IDC_LIST, LBSelChange),
  759. END_RESPONSE_TABLE;
  760.  
  761. void
  762. TItemsDialog::SetupWindow()
  763. {
  764.   CHECK(items != 0);
  765.   pList = new TListBox(this, IDC_LIST);
  766.   CHECK(pList != 0);
  767.   pList->Create();
  768.   for (int i = 0; i < items->GetItemsInContainer(); i++)
  769.     pList->AddString((*items)[i]->GetDescr());
  770. }
  771.  
  772. TItemsDialog::~TItemsDialog() { delete pList; }
  773.  
  774. //
  775. //  TDelUsrDialog: animates the 'Delete User Group' dialog box. Just have
  776. //  to do the error handling, the base class doing the rest:
  777. //
  778.  
  779. void
  780. TDelUsrDialog::CmOk()
  781. {
  782.   nSel = pList->GetSelIndex();
  783.   if (nSel == LB_ERR) {
  784.     MessageBox(
  785.       string(*GetModule(), IDS_ERR_DEL_TXT).c_str(),
  786.       string(*GetModule(), IDS_ERR_DEL_CAP).c_str(),
  787.       MB_OK|MB_ICONHAND);
  788.     ::SetFocus(*pList);
  789.   } else
  790.     TItemsDialog::CmOk();
  791. }
  792.  
  793. //
  794. //  TEdtUsrDialog: animates the 'edit User Group' dialog box. This enable
  795. //  the user to change classname/description of setup items after having
  796. //  created them. Also, generates on demand a C++ example on the clipboard:
  797. //
  798.  
  799.  
  800. DEFINE_RESPONSE_TABLE1(TEdtUsrDialog, TItemsDialog)
  801. END_RESPONSE_TABLE;
  802.  
  803. void
  804. TEdtUsrDialog::LBSelChange()
  805. {
  806.   if (nPrevSel != LB_ERR) {
  807.     char Class[40], Descr[40];
  808.     GetDlgItemText(IDC_DESCR, Descr, sizeof(Descr));
  809.     GetDlgItemText(IDC_CLASS, Class, sizeof(Class));
  810.     (*items)[nPrevSel]->SetDescr(Descr);
  811.     (*items)[nPrevSel]->SetClass(Class);
  812.     pList->SetItemData(nPrevSel, (DWORD)Descr);
  813.   }
  814.   if ((nPrevSel = nSel = pList->GetSelIndex()) != LB_ERR) {
  815.     SetDlgItemText(IDC_DESCR, (*items)[nSel]->GetDescr());
  816.     SetDlgItemText(IDC_CLASS, (*items)[nSel]->GetClass());
  817.   }
  818. }
  819.  
  820. void
  821. TEdtUsrDialog::CmOk()
  822. {
  823.   LBSelChange();
  824.  
  825.   char descr[40], className[40];
  826.  
  827.   GetDlgItemText(IDC_DESCR, descr, sizeof(descr));
  828.   GetDlgItemText(IDC_CLASS, className, sizeof(className));
  829.   CopyToClipboard(this, descr, className);
  830.  
  831.   TItemsDialog::CmOk();
  832. }
  833.